﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using System.Workflow.Activities;
using System.Workflow.ComponentModel;
using Common.Logging;
using LumiSoft.Net.IMAP;
using LumiSoft.Net.IMAP.Client;
using LumiSoft.Net.POP3.Client;
using System.Reflection;

namespace MailCrawler.Workflow
{
    public sealed partial class CheckerWorkflow : SequentialWorkflowActivity
    {
        private ILog _log = LogManager.GetCurrentClassLogger();

        public CheckerWorkflow()
        {
            InitializeComponent();
            SetAllowUnsafeHeaderParsing20();
        }
        public EMail CurrentEMail { get; set; }
        private void GetEmail_ExecuteCode(object sender, EventArgs e)
        {
            CurrentEMail = EmailFetcher.GetEMail();
        }

        private POP3_Client POP3client;
        private int CurrentMessage { get; set; }
        private int CurrentMatch { get; set; }

        private void ConnectToPOP3Service_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                POP3client = new POP3_Client();
                _log.Debug("Connecting to server: " + CurrentEMail.Server + " : " + CurrentEMail.Port + " UsingSSL:" +
                           CurrentEMail.IsSSL);
                POP3client.Connect(CurrentEMail.Server, CurrentEMail.Port, CurrentEMail.IsSSL);
                _log.Debug("Connected");
                _log.Debug("Authenticating with Login: " + CurrentEMail.Login + " Pass: " + CurrentEMail.Password);
                POP3client.Authenticate(CurrentEMail.Login, CurrentEMail.Password, false);
                _log.Debug("Authenticated, there are " + POP3client.Messages.Count + " messages in this email box.");

                CurrentMessage = 0;
                CurrentMatch = 0;
                Matches = new List<string>();
            }
            catch (Exception ex) 
            {
                
                throw new System.Exception(ex.Message);
            }
            
        }

        private LumiSoft.Net.IMAP.Client.IMAP_Client IMAPclient;

        private void ConnectToIMAPService_ExecuteCode(object sender, EventArgs e)
        {
            //try
            //{
            //    IMAPclient = new IMAP_Client();
            //    _log.Debug("Connecting to server: " + CurrentEMail.Server + " : " + CurrentEMail.Port + " UsingSSL:" +
            //               CurrentEMail.IsSSL);
            //    IMAPclient.Connect(CurrentEMail.Server, CurrentEMail.Port, CurrentEMail.IsSSL);
            //    _log.Debug("Connected");
            //    _log.Debug("Authenticating with Login: " + CurrentEMail.Login + " Pass: " + CurrentEMail.Password);
            //    IMAPclient.Login(CurrentEMail.Login, CurrentEMail.Password);
            //    if (IMAPclient.IsAuthenticated)
            //    {
            //        var v = IMAPclient.GetFolders("*");

            //        IMAPclient.SelectFolder("INBOX");
            //        var vv = IMAPclient.SelectedFolder.UidNext;
            //        var fa = new IMAP_Client_FetchArg[2];
            //        fa[0] = new LumiSoft.Net.IMAP.Client.IMAP_Client_FetchArg_Uid();
            //        fa[1] = new LumiSoft.Net.IMAP.Client.IMAP_Client_FetchArg_Body();

            //        var ss = new IMAP_SequenceSet();
            //        ss.Parse(vv.ToString());
            //        var han = new IMAP_Client_FetchHandler();
            //        han.Body += new EventHandler<IMAP_Client_Fetch_Body_EArgs>(han_Body);
            //        IMAPclient.Fetch(false, ss, fa, han);
            //        _log.Debug("Authenticated, there are " + IMAPclient.SelectedFolder.MessagesCount +
            //                   " messages in this email box.");

            //    }

            //    CurrentMessage = 0;
            //    CurrentMatch = 0;
            //    MatchesCount = 0;
            //    Matches = new List<string>();
            //}
            //catch (Exception ex)
            //{
            //    _log.Error(ex);
            //    this.Ex = ex;
            //    throw ex;
            //}
        }

        private void DisconnectFromPOP3Service_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                _log.Debug("Disconnecting and deleting all messages");
                POP3client.Disconnect();
                POP3client.Dispose();
            }
            catch (Exception ex)
            {
                _log.Error(ex);
                this.Ex = ex;
                throw ex;
            }
        }
        private void DisconnectFromIMAPSerivce_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                _log.Debug("Disconnecting and deleting all messages");
                IMAPclient.Disconnect();
                IMAPclient.Dispose();
            }
            catch (Exception ex)
            {
                _log.Error(ex);
                this.Ex = ex;
                throw ex;
            }
        }
        private List<string> Matches=new List<string>();
        public int MatchesCount=0;
        public int MatchesCountFoundLast=0;
        private void FindRuleMatch_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                _log.Debug("Reading email number " + CurrentMessage);
                POP3_ClientMessage message = POP3client.Messages[CurrentMessage];

                MemoryStream ms = new MemoryStream();
                message.MessageToStream(ms);
                StreamReader sr = new StreamReader(ms);
                ms.Seek(0, SeekOrigin.Begin);
                string messagestr = sr.ReadToEnd();
                _log.Debug("Length " + messagestr.Length);


                foreach (var regex in RuleFetcher.Rules)
                {
                    Regex rx = new Regex(regex.rule);
                    MatchCollection mc = rx.Matches(messagestr);
                    foreach (var m in mc)
                    {
                        var st = ((System.Text.RegularExpressions.Match)m).Value;
                        Matches.Add(st);
                    }
                    MatchesCount += mc.Count;
                    MatchesCountFoundLast = mc.Count;
                }
                _log.Debug("Found " + MatchesCount + " matches in this email, marking for deletion.");
                message.MarkForDeletion();
            }
            catch (Exception ex)
            {
                _log.Error(ex);
                this.Ex = ex;
                throw ex;
            }
            finally
            {
                CurrentMessage++;
            }
        }
        public string Currentlink { get; set; }
        int currentTry = 0;
        private void ClickOnMatchedLink_ExecuteCode(object sender, EventArgs e)
        {
            try
            {
                _log.Debug("Founded link: " + Matches[CurrentMatch]);
                Uri link = new Uri(Matches[CurrentMatch]);
                Currentlink = System.Web.HttpUtility.UrlEncode(link.ToString());
                HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(link);
                loHttp.Timeout = 5000;
                foreach (var line in HeaderFetcher.headers)
                {
                    var sub = line.Split(new char[] { ':' }, 2);
                    try
                    {
                        switch (sub[0])
                        {
                            case "User-Agent":
                                loHttp.UserAgent = sub[1];
                                break;
                            case "Accept":
                                loHttp.Accept = sub[1];
                                break;
                            case "Connection":
                                loHttp.KeepAlive = sub[1] == "keep-alive";
                                break;
                            case "Referer":
                                loHttp.Referer = sub[1];
                                break;
                        }
                    }
                    catch
                    {
                        
                    }
                }
                
                loHttp.Proxy = ProxyFetcher.FetchRandomProxy();
                if (loHttp.Proxy == null)
                    _log.Debug("Using NO proxy, as there are none in Proxies.txt.");
                else
                    _log.Debug("Clicking on it using proxy: " + ((WebProxy)loHttp.Proxy).Address);
                HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse();
                StreamReader loResponseStream = new StreamReader(loWebResponse.GetResponseStream());
                string lcHtml = loResponseStream.ReadToEnd();
                loWebResponse.Close();
                loResponseStream.Close();

                _log.Debug("Clicked, respond length: " + lcHtml.Length);

            }
            catch (System.Net.WebException ex)
            {
                _log.Error(ex);
                this.Ex = ex;
                if (++currentTry <= 3)
                    CurrentMatch--;
                else
                    currentTry = 0;
                throw ex;
            }
            catch (Exception ex)
            {
                _log.Error(ex);
                this.Ex = ex;
                throw ex;
            }
            finally
            {
                CurrentMatch++;
            }
        }
        public static bool SetAllowUnsafeHeaderParsing20()
        {
            //Get the assembly that contains the internal class 
            Assembly aNetAssembly = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection));
            if (aNetAssembly != null)
            {
                //Use the assembly in order to get the internal type for the internal class 
                Type aSettingsType = aNetAssembly.GetType("System.Net.Configuration.SettingsSectionInternal");
                if (aSettingsType != null)
                {
                    //Use the internal static property to get an instance of the internal settings class. 
                    //If the static instance isn't created allready the property will create it for us. 
                    object anInstance = aSettingsType.InvokeMember("Section",
                    BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic, null, null, new object[] { });

                    if (anInstance != null)
                    {
                        //Locate the private bool field that tells the framework is unsafe header parsing should be allowed or not 
                        FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (aUseUnsafeHeaderParsing != null)
                        {
                            aUseUnsafeHeaderParsing.SetValue(anInstance, true);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        public static DependencyProperty ExProperty = DependencyProperty.Register("Ex", typeof(System.Exception), typeof(MailCrawler.Workflow.CheckerWorkflow));

        [System.ComponentModel.DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [System.ComponentModel.BrowsableAttribute(true)]
        [System.ComponentModel.CategoryAttribute("Parameters")]
        public Exception Ex
        {
            get
            {
                return ((System.Exception)(base.GetValue(MailCrawler.Workflow.CheckerWorkflow.ExProperty)));
            }
            set
            {
                base.SetValue(MailCrawler.Workflow.CheckerWorkflow.ExProperty, value);
            }
        }

        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {

        }








    }

}
